FIX: Call rustdoc test with the correct cfg flags of a package.
authorJuan Hernández <juan.hernandez.babon@gmail.com>
Mon, 31 Oct 2016 18:15:03 +0000 (19:15 +0100)
committerJuan Hernández <juan.hernandez.babon@gmail.com>
Mon, 31 Oct 2016 21:48:01 +0000 (22:48 +0100)
There was a situation in which if you you had a lib that depends
on a package with features, whenever you ran the tests for the
package the `rustdoc test` call was failing because rustdoc
was called with the root cfg flags, not the package cfg flags.

This fix solves the issue by keeping track of the cfg flags
per package, so the rustdoc command will be generated with
the correct cfg flags.

src/cargo/ops/cargo_rustc/compilation.rs
src/cargo/ops/cargo_rustc/mod.rs
src/cargo/ops/cargo_test.rs
tests/test.rs

index 93dead30743ebd1a3c2a4ad6bf8ef7b2bfd5c0ab..f15032c2336626758c7a845663103822ece01219 100644 (file)
@@ -43,8 +43,8 @@ pub struct Compilation<'cfg> {
 
     pub to_doc_test: Vec<Package>,
 
-    /// Features enabled during this compilation.
-    pub cfgs: HashSet<String>,
+    /// Features per package enabled during this compilation.
+    pub cfgs: HashMap<PackageId, HashSet<String>>,
 
     pub target: String,
 
@@ -63,7 +63,7 @@ impl<'cfg> Compilation<'cfg> {
             binaries: Vec::new(),
             extra_env: HashMap::new(),
             to_doc_test: Vec::new(),
-            cfgs: HashSet::new(),
+            cfgs: HashMap::new(),
             config: config,
             target: String::new(),
         }
index 33f86c0ef1bfa5570726b248d10686e9ef54edc1..26edaae9e4fae10e0b35d10692c9f8c8eda1ab87 100644 (file)
@@ -1,4 +1,4 @@
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 use std::env;
 use std::ffi::{OsStr, OsString};
 use std::fs;
@@ -81,7 +81,6 @@ pub fn compile_targets<'a, 'cfg: 'a>(ws: &Workspace<'cfg>,
         })
     }).collect::<Vec<_>>();
 
-    let root = try!(ws.current());
     let mut cx = try!(Context::new(ws, resolve, packages, config,
                                    build_config, profiles));
 
@@ -142,19 +141,21 @@ pub fn compile_targets<'a, 'cfg: 'a>(ws: &Workspace<'cfg>,
                 cx.compilation.libraries.insert(pkgid.clone(), v);
             }
         }
-    }
 
-    let root_pkg = root.package_id();
-    if let Some(feats) = cx.resolve.features(root_pkg) {
-        cx.compilation.cfgs.extend(feats.iter().map(|feat| {
-            format!("feature=\"{}\"", feat)
-        }));
+        if let Some(feats) = cx.resolve.features(&unit.pkg.package_id()) {
+            for feat in feats.iter() {
+                cx.compilation.cfgs.entry(unit.pkg.package_id().clone())
+                    .or_insert(HashSet::new())
+                    .insert(format!("feature=\"{}\"", feat));
+            }
+        }
     }
 
     for (&(ref pkg, _), output) in cx.build_state.outputs.lock().unwrap().iter() {
-        if pkg == root_pkg {
-            cx.compilation.cfgs.extend(output.cfgs.iter().cloned());
-        }
+        cx.compilation.cfgs.entry(pkg.clone())
+            .or_insert(HashSet::new())
+            .extend(output.cfgs.iter().cloned());
+
         for dir in output.library_paths.iter() {
             cx.compilation.native_dirs.insert(dir.clone());
         }
index 71a22d4e46178f8aba847d6dccd8a4e9b666aaef..f382a1dd128e828adc3e423641a7ea80f00479cb 100644 (file)
@@ -145,8 +145,10 @@ fn run_doc_tests(options: &TestOptions,
                 p.arg("--test-args").arg(&test_args.join(" "));
             }
 
-            for cfg in compilation.cfgs.iter() {
-                p.arg("--cfg").arg(cfg);
+            if let Some(cfgs) = compilation.cfgs.get(&package.package_id()) {
+                for cfg in cfgs.iter() {
+                    p.arg("--cfg").arg(cfg);
+                }
             }
 
             for (_, libs) in compilation.libraries.iter() {
index 2e5d8aa57beddf5de2757ec0d30acb0df60b0167..cefec7e24e02ff4bc38fd3169bd29c24af26bec4 100644 (file)
@@ -2262,3 +2262,73 @@ fn panic_abort_multiple() {
                  .arg("-p").arg("a"),
                 execs().with_status(0));
 }
+
+#[test]
+fn pass_correct_cfgs_flags_to_rustdoc() {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "foo"
+            version = "0.1.0"
+            authors = []
+
+            [features]
+            default = ["a/default"]
+            nightly = ["a/nightly"]
+
+            [dependencies.a]
+            path = "libs/a"
+            default-features = false
+        "#)
+        .file("src/lib.rs", r#"
+            #[cfg(test)]
+            mod tests {
+                #[test]
+                fn it_works() {
+                  assert!(true);
+                }
+            }
+        "#)
+        .file("libs/a/Cargo.toml", r#"
+            [package]
+            name = "a"
+            version = "0.1.0"
+            authors = []
+
+            [features]
+            default = ["serde_codegen"]
+            nightly = ["serde_derive"]
+
+            [dependencies]
+            serde_derive = { version = "0.8", optional = true }
+
+            [build-dependencies]
+            serde_codegen = { version = "0.8", optional = true }
+        "#)
+        .file("libs/a/src/lib.rs", r#"
+            #[cfg(feature = "serde_derive")]
+            const MSG: &'static str = "This is safe";
+
+            #[cfg(feature = "serde_codegen")]
+            const MSG: &'static str = "This is risky";
+
+            pub fn get() -> &'static str {
+                MSG
+            }
+        "#);
+
+    assert_that(p.cargo_process("test")
+                .arg("--package").arg("a")
+                .arg("--verbose"),
+                execs().with_status(0)
+                       .with_stderr_contains("\
+[DOCTEST] a
+[RUNNING] `rustdoc --test [..]--cfg feature=\\\"serde_codegen\\\"[..]`"));
+
+    assert_that(p.cargo_process("test")
+                .arg("--verbose"),
+                execs().with_status(0)
+                       .with_stderr_contains("\
+[DOCTEST] foo
+[RUNNING] `rustdoc --test [..]--cfg feature=\\\"a\\\"[..]`"));
+}